package com.CTAtracker.android.Fragments;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

import com.CTAtracker.android.R;
import com.CTAtracker.android.Activities.SeveralStationActivity;
import com.CTAtracker.android.Activities.SlidingActivity;
import com.CTAtracker.android.Activities.StationActivity;
import com.CTAtracker.android.Adapters.StationsAroundItemAdapter;
import com.CTAtracker.android.DAO.StationDataSource;
import com.CTAtracker.android.Models.AroundStation;
import com.CTAtracker.android.Models.ColorStation;
import com.CTAtracker.android.Models.Position;

/**
 * Fragment regarding the Station Around the user
 */
public class AroundFragment extends Fragment implements LocationListener, Comparator<AroundStation> {

	/**
	 * Log
	 */
	private static final String TAG = "AroundFragment";
	/**
	 * Minimum among of time before refreshing the location
	 * The time is in millisecond
	 * 5 minutes
	 */
	private final int MIN_TIME = 1000 * 60 * 5; 
	/**
	 * Minimum distance before refreshing the location
	 * The distance is in meters
	 * 100 meters
	 */
	private final int MIN_DISTANCE = 100; 
	/**
	 * List of station 
	 */
	private ArrayList<AroundStation> _listStations; 
			
	/**
	 * the view of the list of stations
	 */
	private ListView _listViewStations;
	/**
	 * The source of the data for the stations
	 */
	private StationDataSource _stationDataSource; 
			
	/**
	 * Adapter to the listView of the fragment 
	 */
	private StationsAroundItemAdapter _adapter;
	/**
	 * Name of the provider
	 */
	private String _provider;
	/**
	 * Location of the user handle by the service of the provier
	 */
	private Location _location;
	/**
	 * The service of the location manager 
	 */
	private LocationManager _service;
	
	private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
		public void onItemClick(AdapterView parent, View v, int position, long id) {
			// 1 station = 2 stops => 2 colors
			if (_listStations.get(position).getListColorStation().size() == 2){
				Intent intent = new Intent((SlidingActivity)getActivity(), StationActivity.class);
				intent.putExtra("idStation", _listStations.get(position).getStationId());
				intent.putExtra("lineId", _listStations.get(position).get_line_id());
				startActivity(intent);
			} else {
				Intent intent = new Intent((SlidingActivity)getActivity(), SeveralStationActivity.class);
				intent.putExtra("parentId", _listStations.get(position).get_parent_stop_id());
				intent.putExtra("nameStation", _listStations.get(position).get_name());
				startActivity(intent);	
			}
		}
	};
	
	
	/**
	 * Called when we create the view. Need to instantiate the data and the location service
	 */
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		/* Instantiate data */
		_listStations = new ArrayList<AroundStation>();
		_stationDataSource = new StationDataSource(getActivity());
		_adapter = new StationsAroundItemAdapter(getActivity(), R.layout.station_row, _listStations);
		_adapter.setNotifyOnChange(true);
		
		/* Instantiate Location */
		_location = null;
		// Get the location manager
		_service = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
		boolean enabledGPS = _service.isProviderEnabled(LocationManager.GPS_PROVIDER);
		boolean enabledNetWork = _service.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

		// Check if both service are enabled and if not send user to the GSP settings
		if (!enabledGPS && !enabledNetWork) {
			Toast.makeText(getActivity(), "Please enable location to check the stations around", Toast.LENGTH_LONG).show();
			Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
			startActivity(intent);
		} 

		// Register the listener with the Location Manager to receive location updates
		if (enabledNetWork){
			_service.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE, this);
		}
		if (enabledGPS){
			_service.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, MIN_DISTANCE, this);
		}
		
		Criteria criteria = new Criteria();
		criteria.setPowerRequirement(Criteria.POWER_LOW); 
		criteria.setSpeedAccuracy(Criteria.ACCURACY_COARSE);
		_provider = _service.getBestProvider(criteria, true);
		// TODO don't get the last know location / set a new method 
		_location = _service.getLastKnownLocation(_provider);
		
		
		// Initialize the location fields
		if (_location != null) {
			onLocationChanged(_location);
		} else {
			// location not available
			Toast.makeText(getActivity(), "Trying to retrive location", Toast.LENGTH_LONG).show();
		}

		return inflater.inflate(R.layout.around, container, false);
	}

	/**
	 * Called when the view is started. Link the element of the view to the adapter
	 */
	@Override
	public void onStart() {
		super.onStart();		

		_listViewStations = (ListView) getView().findViewById(R.id.listViewStations);
		_listViewStations.setAdapter(_adapter);
		
		_listViewStations.setOnItemClickListener(mMessageClickedHandler);

	}
	

	@Override
	public void onResume() {
		super.onResume();
		_listStations = new ArrayList<AroundStation>();
		_stationDataSource = new StationDataSource(getActivity());
		_adapter = new StationsAroundItemAdapter(getActivity(), R.layout.station_row, _listStations);
		_adapter.setNotifyOnChange(true);
		
		
		_service = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
		Criteria criteria = new Criteria();
		criteria.setPowerRequirement(Criteria.POWER_LOW); 
		criteria.setSpeedAccuracy(Criteria.ACCURACY_COARSE);
		_provider = _service.getBestProvider(criteria, true);
		_service.requestLocationUpdates(_provider, MIN_TIME, MIN_DISTANCE, this);
		
		_location = _service.getLastKnownLocation(_provider);
	}

	@Override
	public void onDetach() {
		super.onDetach();
		// Remove the listener you previously added
		_service.removeUpdates(this);
	}

	@Override
	public void onPause() {
		super.onPause();
		_service.removeUpdates(this);
	}

	@Override
	public void onStop() {
		super.onStop();
		_service.removeUpdates(this);
	}

	@Override
	public void onLocationChanged(Location location) {
		_location = location;
		Position position = new Position(location.getLatitude(), location.getLongitude());
		double radius = 2.0;
		int maxStation = 5; 
		_listStations.clear();
		_stationDataSource.open(); 
		_listStations = _stationDataSource.getAllStationAround();
		
		// set all the distance and the color
		for (int i=0; i< _listStations.size(); i++){
			_listStations.get(i).setDistance(
					position.distance(_listStations.get(i).get_position()));
			ArrayList<ColorStation> listColor = _stationDataSource.getListColorStation(_listStations.get(i).get_parent_stop_id());
			_listStations.get(i).addColor(listColor);
		}
		
		_stationDataSource.close();
		_listStations = closestStation(_listStations, position, radius, maxStation);
		Collections.sort(_listStations, this);
		_adapter.clear();
		_adapter.addAll(_listStations);
		_adapter.notifyDataSetChanged();
	}

	/**
	 * create a new list of the closest station to the user
	 * @param listStations the list of all the stations
	 * @param pos the position of the user
	 * @param radius the maximum radius of the closest station  
	 * @param maxStation the number maximal of stations
	 * @return the list of the closest stations to the user
	 */
	private ArrayList<AroundStation> closestStation(ArrayList<AroundStation> listStations, Position pos, double radius, int maxStation) {
		ArrayList<AroundStation> finalListStation = new ArrayList<AroundStation>();
		for(int i=0; i< listStations.size(); i++){
			// if the station is in the range
			if (listStations.get(i).getDistance() < radius){
				// there is enough space to add the station without looking further 
				if (finalListStation.size() < maxStation){
					finalListStation.add(listStations.get(i));
				}
				// We need to look further
				else{
					// is the position of the station is closer than the station in the final list
					listStations.get(i).iscloser(finalListStation, pos);
				}
			}
		}
		return finalListStation;
	}

	@Override
	public void onProviderEnabled(String provider) {
		Toast.makeText(getActivity(), "Enabled new provider " + provider,Toast.LENGTH_SHORT).show();

	}

	@Override
	public void onProviderDisabled(String provider) {
		Toast.makeText(getActivity(), "Disabled provider " + provider,Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub
		Log.i(TAG, "Change of status to " + status);
	}

	@Override
	public int compare(AroundStation lhs, AroundStation rhs) {
		return lhs.compareTo(rhs);
	}
}
